/*
 * @Author: soon.liao
 * @Date: 2024-02-05 21:44:50
 * @LastEditors: soon.liao
 * @LastEditTime: 2025-03-16 21:24:50
 * @FilePath: \my-car\main\l9110s.c
 * @Description: NA
 * NA
 * Copyright (c) 2024 by soon.liao  , All Rights Reserved.
 */
#include "esp_log.h"
#include "esp_system.h"
#include "driver/ledc.h"
#include "driver/gpio.h"

#include "l9110s.h"

static const char *TAG = "l9110s";

// PWM配置
#define PWM_TIMER LEDC_TIMER_0
#define PWM_MODE LEDC_LOW_SPEED_MODE
#define PWM_CHANNEL LEDC_CHANNEL_0
#define PWM_DUTY_RES LEDC_TIMER_8_BIT // 分辨率
#define PWM_FREQ 1000                 // 频率1kHz

// 控制单个电机的速度和方向
void motor_l9110s_pwm_control(int gpio, ledc_channel_t channel_num, ledc_timer_t timer_num, uint32_t speed)
{
    // 配置PWM

    ledc_timer_config_t ledc_timer = {
        .speed_mode = PWM_MODE,
        .timer_num = timer_num,
        .freq_hz = PWM_FREQ,             // 设置PWM频率
        .duty_resolution = PWM_DUTY_RES, // 设置PWM分辨率
    };

    ledc_timer_config(&ledc_timer);
    ledc_channel_config_t ledc_channel = {
        .speed_mode = PWM_MODE,
        .channel = channel_num,
        .timer_sel = PWM_TIMER,
        .intr_type = LEDC_INTR_DISABLE,
        .gpio_num = gpio,
        .duty = 0, // 初始占空比
        .hpoint = 0};
    ledc_channel_config(&ledc_channel);
    // speed的值应该在0到(1 << PWM_DUTY_RES) - 1之间

    // 这里我们假设PWM_DUTY_RES为13，所以speed的最大值为8191

    if (speed > (1 << PWM_DUTY_RES) - 1)
    {
        speed = (1 << PWM_DUTY_RES) - 1;
    }

    // 设置PWM占空比
    ledc_set_duty(PWM_MODE, channel_num, speed);
    ledc_update_duty(PWM_MODE, channel_num);
}

void motor_l9110s_gpio_control(gpio_num_t gpio, uint32_t val)
{
    gpio_reset_pin(gpio);
    gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
    gpio_set_level(gpio, val);
}

void motor_l9110s_init(void)
{
    ESP_LOGI(TAG, "%s", __FUNCTION__);
    motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_FOR, 0);
    motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_BAK, 0);

    motor_l9110s_gpio_control(MOTOR_LEFT_REAR_FOR, 0);
    motor_l9110s_gpio_control(MOTOR_LEFT_REAR_BAK, 0);

    motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_FOR, 0);
    motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_BAK, 0);

    motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_FOR, 0);
    motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_BAK, 0);
}

void motor_l9110s_standby(MotorPosition position)
{
    ESP_LOGI(TAG, "%s %d", __FUNCTION__, position);
    switch (position)
    {
    case LEFT_FRONT:
        /* code */
        motor_l9110s_pwm_control(MOTOR_LEFT_FRONT_FOR, LEDC_CHANNEL_0, LEDC_TIMER_0, 0);
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_FOR, 0);
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_BAK, 0);
        break;
    case LEFT_REAR:
        /* code */
        motor_l9110s_pwm_control(MOTOR_LEFT_REAR_FOR, LEDC_CHANNEL_1, LEDC_TIMER_1, 0);
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_FOR, 0);
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_BAK, 0);
        break;
    case RIGHT_FRONT:
        /* code */
        motor_l9110s_pwm_control(MOTOR_RIGHT_FRONT_FOR, LEDC_CHANNEL_2, LEDC_TIMER_2, 0);
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_FOR, 0);
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_BAK, 0);
        break;
    case RIGHT_REAR:
        /* code */
        motor_l9110s_pwm_control(MOTOR_RIGHT_REAR_FOR, LEDC_CHANNEL_3, LEDC_TIMER_3, 0);
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_FOR, 0);
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_BAK, 0);
        break;
    default:
        break;
    }
}

void motor_l9110s_foreward(MotorPosition position, uint32_t speed)
{
    ESP_LOGI(TAG, "%s %d", __FUNCTION__, position);
    switch (position)
    {
    case LEFT_FRONT:
        /* code */
        motor_l9110s_pwm_control(MOTOR_LEFT_FRONT_FOR, LEDC_CHANNEL_0, LEDC_TIMER_0, speed);
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_BAK, 0);
        break;
    case LEFT_REAR:
        /* code */
        motor_l9110s_pwm_control(MOTOR_LEFT_REAR_FOR, LEDC_CHANNEL_1, LEDC_TIMER_1, speed);
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_BAK, 0);
        break;
    case RIGHT_FRONT:
        /* code */
        motor_l9110s_pwm_control(MOTOR_RIGHT_FRONT_FOR, LEDC_CHANNEL_2, LEDC_TIMER_2, speed);
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_BAK, 0);
        break;
    case RIGHT_REAR:
        /* code */
        motor_l9110s_pwm_control(MOTOR_RIGHT_REAR_FOR, LEDC_CHANNEL_3, LEDC_TIMER_3, speed);
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_BAK, 0);
        break;
    default:
        break;
    }
}
void motor_l9110s_reversal(MotorPosition position, uint32_t speed)
{
    ESP_LOGI(TAG, "%s %d", __FUNCTION__, position);
    switch (position)
    {
    case LEFT_FRONT:
        /* code */
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_FOR, 0);
        motor_l9110s_pwm_control(MOTOR_LEFT_FRONT_BAK, LEDC_CHANNEL_0, LEDC_TIMER_0, speed);
        break;
    case LEFT_REAR:
        /* code */
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_FOR, 0);
        motor_l9110s_pwm_control(MOTOR_LEFT_REAR_BAK, LEDC_CHANNEL_1, LEDC_TIMER_1, speed);
        break;
    case RIGHT_FRONT:
        /* code */
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_FOR, 0);
        motor_l9110s_pwm_control(MOTOR_RIGHT_FRONT_BAK, LEDC_CHANNEL_2, LEDC_TIMER_2, speed);
        break;
    case RIGHT_REAR:
        /* code */
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_FOR, 0);
        motor_l9110s_pwm_control(MOTOR_RIGHT_REAR_BAK, LEDC_CHANNEL_3, LEDC_TIMER_3, speed);
        break;
    default:
        break;
    }
}

void motor_l9110s_brake(MotorPosition position)
{
    ESP_LOGI(TAG, "%s %d", __FUNCTION__, position);
    switch (position)
    {
    case LEFT_FRONT:
        /* code */
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_FOR, 1);
        motor_l9110s_gpio_control(MOTOR_LEFT_FRONT_BAK, 1);
        break;
    case LEFT_REAR:
        /* code */
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_FOR, 1);
        motor_l9110s_gpio_control(MOTOR_LEFT_REAR_BAK, 1);
        break;
    case RIGHT_FRONT:
        /* code */
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_FOR, 1);
        motor_l9110s_gpio_control(MOTOR_RIGHT_FRONT_BAK, 1);
        break;
    case RIGHT_REAR:
        /* code */
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_FOR, 1);
        motor_l9110s_gpio_control(MOTOR_RIGHT_REAR_BAK, 1);
        break;
    default:
        break;
    }
}

void motor_l9110s_control(MotorPosition position, MotorFunction function, uint32_t speed)
{
    ESP_LOGI(TAG, "%s position=%d function =%d", __FUNCTION__, position, function);
    switch (function)
    {
    case STANDBY:
        /* code */
        motor_l9110s_standby(position);
        break;
    case FOREWARD:
        /* code */
        motor_l9110s_foreward(position, speed);
        break;
    case REVERSAL:
        /* code */
        motor_l9110s_reversal(position, speed);
        break;
    case BRAKE:
        /* code */
        motor_l9110s_brake(position);
        break;
    default:
        break;
    }
}